import { defineStore } from "pinia";
import CryptoJS from "crypto-js";
import JSEncrypt from "jsencrypt/bin/jsencrypt.min";

export default defineStore("cryptoStore", {
  state: () => ({
    backendPublicKey: import.meta.env.VITE_APP_PUBLIC_KEY, // 后端公钥（字符串）
    frontendKeyAndIvArray: [], // 前端 AES 密钥与 IV 组合
  }),
  actions: {
    // 生成前端 AES 密钥 与 IV
    generateFrontendKey(url) {
      // 生成 32 字节 (256 位) 的随机密钥
      const _AesKey = CryptoJS.lib.WordArray.random(32);
      const frontendKey = CryptoJS.enc.Base64.stringify(_AesKey);

      // 生成 16 字节 (128 位) 的随机 IV
      const _iv = CryptoJS.lib.WordArray.random(16);
      const frontendIv = CryptoJS.enc.Base64.stringify(_iv);

      this.frontendKeyAndIvArray = [
        ...this.frontendKeyAndIvArray,
        {
          url,
          key: frontendKey,
          iv: frontendIv,
        },
      ];

      return { key: frontendKey, iv: frontendIv };
    },

    // 请求前：准备加密，返回 { key, iv, data }
    prepareEncryptedPayload(url, datajson) {
      // 生成前端 key 与 iv
      const frontendKeyIv = this.generateFrontendKey(url);

      const text =
        typeof datajson === "string" ? datajson : JSON.stringify(datajson);

      // 用前端 key + iv 进行 AES-CBC 加密 data
      const dataCipher = CryptoJS.AES.encrypt(
        text,
        CryptoJS.enc.Base64.parse(frontendKeyIv.key),
        {
          iv: CryptoJS.enc.Base64.parse(frontendKeyIv.iv),
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7,
        }
      ).toString();

      // 用后端 RSA 公钥对前端 AES 密钥进行加密，生成 key（RSA）
      const rsa = new JSEncrypt();
      rsa.setPublicKey(this.backendPublicKey);
      const encryptKey = rsa.encrypt(frontendKeyIv.key);
      if (!encryptKey) throw new Error("RSA 公钥加密前端密钥失败");

      return {
        encryptKey,
        iv: frontendKeyIv.iv,
        data: dataCipher,
      };
    },

    // 响应后：使用前端 key + iv 解密 data，并销毁前端 key 与 iv
    decryptAndDestroy(requestConfig, ciphertext) {
      // 不需要解密
      const notCrypto = requestConfig.headers.notCrypto === false;
      if (notCrypto) return ciphertext;
      // 响应数据为空
      if (!ciphertext) return null;

      const frontendKeyIv = this.frontendKeyAndIvArray.find(
        (item) => item.iv === requestConfig.headers["X-Encrypt-Iv"]
      );

      if (!frontendKeyIv || !frontendKeyIv.key || !frontendKeyIv.iv) {
        throw new Error("前端密钥/IV不存在");
      }

      const bytes = CryptoJS.AES.decrypt(
        ciphertext,
        CryptoJS.enc.Base64.parse(frontendKeyIv.key),
        {
          iv: CryptoJS.enc.Base64.parse(frontendKeyIv.iv),
          mode: CryptoJS.mode.CBC,
          padding: CryptoJS.pad.Pkcs7,
        }
      );
      const plain = bytes.toString(CryptoJS.enc.Utf8);

      // 解密成功后销毁前端 key 与 iv
      this.destroyCurrentKeyAndIv(frontendKeyIv.iv);

      try {
        return JSON.parse(plain);
      } catch (e) {
        return plain;
      }
    },
    // 销毁当前 key 与 iv
    destroyCurrentKeyAndIv(iv) {
      this.frontendKeyAndIvArray = this.frontendKeyAndIvArray.filter(
        (item) => item.iv !== iv
      );
    },
  },
});
